/*
 * This file is part of the hptx distribution (https://github.com/cectc/htpx).
 * Copyright 2022 CECTC, Inc.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this
 * program. If not, see <https://www.gnu.org/licenses/>.
 */

package config

import (
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/cectc/dbpack/pkg/log"
	clientv3 "go.etcd.io/etcd/client/v3"

	"github.com/cectc/hptx/pkg/misc"
)

var distributedTransaction *DistributedTransaction

type DistributedTransaction struct {
	ApplicationID                    string `yaml:"appid" json:"appid"`
	RetryDeadThreshold               int64  `yaml:"retry_dead_threshold" json:"retry_dead_threshold"`
	RollbackRetryTimeoutUnlockEnable bool   `yaml:"rollback_retry_timeout_unlock_enable" json:"rollback_retry_timeout_unlock_enable"`

	EtcdConfig clientv3.Config `yaml:"etcd_config" json:"etcd_config"`

	ATConfig ATConfig `yaml:"at" json:"at,omitempty"`
	TMConfig TMConfig `yaml:"tm" json:"tm,omitempty"`
}

type ATConfig struct {
	DSN                 string        `yaml:"dsn" json:"dsn,omitempty"`
	ReportRetryCount    int           `default:"5" yaml:"reportRetryCount" json:"reportRetryCount,omitempty"`
	ReportSuccessEnable bool          `default:"false" yaml:"reportSuccessEnable" json:"reportSuccessEnable,omitempty"`
	LockRetryInterval   time.Duration `default:"10ms" yaml:"lockRetryInterval" json:"lockRetryInterval,omitempty"`
	LockRetryTimes      int           `default:"30" yaml:"lockRetryTimes" json:"lockRetryTimes,omitempty"`
}

type TMConfig struct {
	CommitRetryCount   int32 `default:"5" yaml:"commitRetryCount" json:"commitRetryCount,omitempty"`
	RollbackRetryCount int32 `default:"5" yaml:"rollbackRetryCount" json:"rollbackRetryCount,omitempty"`
}

// GetTMConfig return TMConfig
func GetTMConfig() TMConfig {
	if distributedTransaction == nil {
		panic("please init client config")
	}
	return distributedTransaction.TMConfig
}

// GetATConfig return ATConfig
func GetATConfig() ATConfig {
	if distributedTransaction == nil {
		panic("please init client config")
	}
	return distributedTransaction.ATConfig
}

// parseClientConfig parses an input configuration yaml document into a ClientConfig struct
//
// Environment variables may be used to override configuration parameters other than version,
// following the scheme below:
// DistributedTransaction.Abc may be replaced by the value of HPTX_ABC,
// DistributedTransaction.Abc.Xyz may be replaced by the value of HPTX_ABC_XYZ, and so forth
func parseClientConfig(rd io.Reader) (*DistributedTransaction, error) {
	in, err := ioutil.ReadAll(rd)
	if err != nil {
		return nil, err
	}

	p := misc.NewParser("HPTX")

	config := new(DistributedTransaction)
	err = p.Parse(in, config)
	if err != nil {
		return nil, err
	}

	return config, nil
}

// InitDistributedTransaction init configuration from a file path
func InitDistributedTransaction(configurationPath string) *DistributedTransaction {
	fp, err := os.Open(configurationPath)
	if err != nil {
		log.Fatalf("open configuration file fail, %v", err)
	}

	config, err := parseClientConfig(fp)
	if err != nil {
		log.Fatalf("error parsing %s: %v", configurationPath, err)
	}

	defer func() {
		err = fp.Close()
		if err != nil {
			log.Error(err)
		}
	}()

	distributedTransaction = config
	return distributedTransaction
}

func SetClientConfig(config *DistributedTransaction) {
	distributedTransaction = config
}
